package com.sky.loveshop.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.shortlink.GenerateShortLinkRequest;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.sky.loveshop.entity.MeiTuanOrder;
import com.sky.loveshop.entity.OpenDoorHistory;
import com.sky.loveshop.entity.Shop;
import com.sky.loveshop.entity.WxMiniUser;
import com.sky.loveshop.entity.exception.BizException;
import com.sky.loveshop.entity.exception.BizExceptionEnum;
import com.sky.loveshop.entity.vo.DriverOpenDoorVO;
import com.sky.loveshop.entity.vo.WxMiniUserVO;
import com.sky.loveshop.entity.weChat.LogInRequest;
import com.sky.loveshop.entity.weChat.OpenDoorRequest;
import com.sky.loveshop.entity.weChat.ShortLinkRequest;
import com.sky.loveshop.entity.weChat.WXACodeUnLimitRequest;
import com.sky.loveshop.mapper.WxMiniUserMapper;
import com.sky.loveshop.service.*;
import com.sky.loveshop.utils.DistanceUtils;
import com.sky.loveshop.utils.QiYeWeChatSendMsgUtil;
import com.sky.loveshop.utils.TokenManager;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;

import static com.sky.loveshop.entity.common.SysConstants.OPEN_DOOR_QI_YE_WECHAT_GROUP_01_KEY;

/**
 * @author xcy
 * @version V1.0
 * @description
 * @date 2024/10/30 21:12
 */
@Slf4j
@Service
public class WeChatMiniServiceImpl implements WeChatMiniService {

    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private WxMiniUserMapper wxMiniUserMapper;
    @Autowired
    private ShopService shopService;
    @Autowired
    private IotService iotService;
    @Autowired
    private OpenDoorHistoryService openDoorHistoryService;
    @Autowired
    private MtService mtService;
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private QiYeWeChatSendMsgUtil qiYeWeChatSendMsgUtil;

    @Override
    public WxMiniUserVO wxLoginOrRegister(LogInRequest request) {
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(request.getCode());
            String openId = sessionInfo.getOpenid();
            log.info("wxLoginOrRegister openId = {}", openId);
            Example example = new Example(WxMiniUser.class);
            example.createCriteria().andEqualTo("openId", openId);
            WxMiniUser wxMiniUser = wxMiniUserMapper.selectOneByExample(example);
            WxMiniUserVO vo = new WxMiniUserVO();
            if (null == wxMiniUser) {
                log.info("wxLoginOrRegister 没有注册此用户，进行注册");
                WxMiniUser user = new WxMiniUser();
                user.setOpenId(openId);
                user.setRegisterTime(new Date());
                wxMiniUserMapper.insert(user);
                // 生成token
                String token = tokenManager.generateToken(user);
                BeanUtils.copyProperties(user, vo);
                vo.setToken(token);
                return vo;
            } else {
                log.info("wxLoginOrRegister wxLogin openId={} 微信小程序登录 用户信息={}", openId, JSONUtil.toJsonStr(wxMiniUser));
                // 生成token
                String token = tokenManager.generateToken(wxMiniUser);
                BeanUtils.copyProperties(wxMiniUser, vo);
                vo.setToken(token);
                return vo;
            }
        } catch (Exception e) {
            log.error("wxLoginOrRegister 小程序登录code:{} 出现异常:{}", request.getCode(), e);
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String getShortLink(ShortLinkRequest request) throws BizException {
        String shortLink = "";
        try {
            GenerateShortLinkRequest build = GenerateShortLinkRequest.builder()
                    .pageUrl(request.getPageUrl())
                    .pageTitle(request.getPageTitle())
                    .isPermanent(request.getIsPermanent()).build();

            log.info("getShortLinkParam = {}", JSONUtil.toJsonStr(build));
            shortLink = wxMaService.getLinkService().generateShortLink(build);
            log.info("getShortLinkResult = {}", shortLink);
        } catch (Exception e) {
            log.error("getShortLinkError", e);
            e.printStackTrace();
            throw new BizException(BizExceptionEnum.WX_API_UN_AUTHORIZED);
        }
        return shortLink;
    }

    @Override
    public byte[] getWXACodeUnLimit(WXACodeUnLimitRequest request) throws BizException {
        /*String generate;
        WxMaGenerateSchemeRequest.JumpWxa jumpWxa = WxMaGenerateSchemeRequest.JumpWxa.newBuilder()
                .path(request.getPage())
                .query(request.getScene())
                .envVersion(request.getEnv_version()).build();
        WxMaGenerateSchemeRequest build = WxMaGenerateSchemeRequest.newBuilder().jumpWxa(jumpWxa).isExpire(Boolean.FALSE).build();
         */
        try {
            //generate = wxMaService.getWxMaSchemeService().generate(build);
            byte[] qrCodeByte = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(request.getScene(), request.getPage(), request.getCheck_path(), request.getEnv_version(), 430, true, null, true);
            return qrCodeByte;
        } catch (Exception e) {
            log.error("getWXACodeUnLimit Error 获取微信小程序码异常", e);
            e.printStackTrace();
            throw new BizException(BizExceptionEnum.GET_WXA_CODE_UN_LIMIT_ERROR);
        }
    }

    @Override
    public Integer wxGetUserPhoneNumber(LogInRequest request) throws BizException {
        Integer shopId = request.getShopId();
        double lnt1 = request.getLnt();
        double lat1 = request.getLat();
        //获取openId、unionId、session_key
        WxMaJscode2SessionResult sessionInfo;
        try {
            sessionInfo = wxMaService.getUserService().getSessionInfo(request.getCode());
            log.info("小程序根据code:【{}】获取用户openId:【{}】成功", request.getCode(), sessionInfo.getOpenid());
        } catch (WxErrorException e) {
            log.error("小程序获取用户信息异常:{}", e.getMessage(), e);
            e.printStackTrace();
            throw new BizException(BizExceptionEnum.WX_GET_SESSION_INFO_ERROR);
        }
        String openId = sessionInfo.getOpenid();
        String sessionKey = sessionInfo.getSessionKey();
        // 解密小程序密文数据获取手机号信息
        WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNoInfo(sessionKey, request.getEncryptedData(), request.getIv());
        String phoneNumber = phoneInfo.getPurePhoneNumber();
        log.info("小程序获取到用户手机号【{}】成功", phoneNumber);

        Example example = new Example(WxMiniUser.class);
        example.createCriteria().andEqualTo("openId", openId);
        WxMiniUser wxMiniUser = wxMiniUserMapper.selectOneByExample(example);
        if (null == wxMiniUser) {
            log.info("用户不存在 则进行 注册");
            WxMiniUser user = new WxMiniUser();
            user.setOpenId(openId);
            user.setPhone(phoneNumber);
            user.setRegisterTime(new Date());
            wxMiniUserMapper.insert(user);
        } else {
            wxMiniUser.setPhone(phoneNumber);
            wxMiniUserMapper.updateByPrimaryKey(wxMiniUser);
        }

        // 计算用户所在位置是否在商店附近100米范围内
        Shop shop = shopService.getShopById(shopId);
        Double lnt2 = shop.getLnt();
        Double lat2 = shop.getLat();
        double distance = DistanceUtils.getDistanceByHaversine(lnt1, lat1, lnt2, lat2);

        OpenDoorHistory history = new OpenDoorHistory();
        history.setWxMiniUserId(wxMiniUser.getId());
        history.setPhone(phoneNumber);
        history.setShopId(shopId);
        history.setShopName(shop.getName());
        history.setOpenTime(new Date());
        history.setLocation(lnt1 + "," + lat1);
        history.setSendResult(0);
        history.setOpenType(1);
        openDoorHistoryService.addOpenDoorHistory(history);

        Integer id = history.getId();
        log.info("addOpenDoorHistory Id 主键id返回 = {}", id);

        if (distance > 1) {
            log.info("wxGetNewPhoneNoInfoOpenDoor Error 门店id={} 门店经纬度=【{},{}】 用户所在经纬度=【{},{}】 距离={}千米", shopId, lnt2, lat2, lnt1, lat1, distance);
            throw new BizException(BizExceptionEnum.DISTANCE_MUST_IN_100);
        } else {
            // 直接发起开门指令
            String result = iotService.userOpenDoorByMini(shopId, phoneNumber);
            if ("下发成功".equals(result)) {
                // 更新状态为下发成功
                history.setSendResult(1);
                history.setUpdateTime(new Date());
                openDoorHistoryService.updateOpenDoorHistoryById(history);

                String msg = assembleOpenDoorMsg(shop.getName(), shop.getAddress(), "门禁小程序新用户扫码后开门", DateUtil.formatDateTime(new Date()), phoneNumber);
                qiYeWeChatSendMsgUtil.sendMarkdownMsg(OPEN_DOOR_QI_YE_WECHAT_GROUP_01_KEY, msg);
            }
        }
        return 1;
    }

    /**
     * 组装开门通知消息
     *
     * @param shopName 商店名称
     * @param address  商店地址
     * @param openType 开门类型 用户扫码开门|骑手扫码开门|后台管理开门|用户线下购买支付成功后开门|骑手核销完成后开门
     * @param openTime 开门时间
     * @param openTime 用户手机号
     */
    private String assembleOpenDoorMsg(String shopName, String address, String openType, String openTime, String phone) {
        StringBuilder msg = new StringBuilder();
        msg.append("#### 门店开门通知\n");
        msg.append(">商店名称：").append(shopName).append("\n");
        msg.append(">商店地址：").append(address).append("\n");
        msg.append(">开门类型：").append(openType).append("\n");
        msg.append(">开门时间：").append(openTime).append("\n");
        msg.append(">用户手机：").append(phone).append("\n");
        return msg.toString();
    }

    @Override
    public WxMiniUser wxGetNewPhone(LogInRequest request) throws BizException {
        String code = request.getCode();
        Integer userId = request.getUserId();
        //获取openId、unionId、session_key
        WxMaPhoneNumberInfo newPhoneNoInfo = null;
        try {
            newPhoneNoInfo = wxMaService.getUserService().getNewPhoneNoInfo(code);
        } catch (Exception e) {
            log.error("wxGetNewPhoneNoInfo error 通过code换取手机号报错 {}", code, e);
            //throw new BizException(BizExceptionEnum.WX_GET_NEW_PHONE_NO_INFO_ERROR);
        }
        String phoneNumber = newPhoneNoInfo.getPhoneNumber();
        log.info("小程序获取到用户手机号【{}】成功", phoneNumber);

        WxMiniUser wxMiniUser = wxMiniUserMapper.selectByPrimaryKey(userId);

        if (null == wxMiniUser) {
            log.info("用户不存在 则进行 注册");
            WxMiniUser user = new WxMiniUser();
            user.setPhone(phoneNumber);
            user.setRegisterTime(new Date());
            wxMiniUserMapper.insert(user);
        } else {
            wxMiniUser.setPhone(phoneNumber);
            wxMiniUserMapper.updateByPrimaryKey(wxMiniUser);
        }
        return wxMiniUser;
    }

    @Override
    public Integer userOpenDoor(LogInRequest request) throws BizException {
        Integer shopId = request.getShopId();
        double lnt1 = request.getLnt();
        double lat1 = request.getLat();
        Integer userId = request.getUserId();
        String phone = request.getPhone();

        // 计算用户所在位置是否在商店附近100米范围内
        Shop shop = shopService.getShopById(shopId);
        Double lnt2 = shop.getLnt();
        Double lat2 = shop.getLat();
        double distance = DistanceUtils.getDistanceByHaversine(lnt1, lat1, lnt2, lat2);

        OpenDoorHistory history = new OpenDoorHistory();
        history.setWxMiniUserId(userId);
        history.setPhone(phone);
        history.setShopId(shopId);
        history.setShopName(shop.getName());
        history.setOpenTime(new Date());
        history.setLocation(lnt1 + "," + lat1);
        history.setSendResult(0);
        history.setOpenType(1);
        openDoorHistoryService.addOpenDoorHistory(history);

        Integer id = history.getId();
        log.info("addOpenDoorHistory Id 主键id返回 = {}", id);

        if (distance > 1) {
            log.info("userOpenDoor Error 距离门店距离太远 门店id={},门店经纬度=【{},{}】用户所在经纬度=【{},{}】距离={}千米,phone={}", shopId, lnt2, lat2, lnt1, lat1, distance, phone);
            throw new BizException(BizExceptionEnum.DISTANCE_MUST_IN_100);
        } else {
            // 直接发起开门指令
            String result = iotService.userOpenDoorByMini(shopId, phone);
            log.info("userOpenDoor 开门 门店id={},门店经纬度=【{},{}】用户所在经纬度=【{},{}】距离={}千米,phone={},开门响应={}", shopId, lnt2, lat2, lnt1, lat1, distance, phone, result);
            if ("发送成功".equals(result)) {
                // 更新状态为下发成功
                history.setSendResult(1);
                history.setUpdateTime(new Date());
                openDoorHistoryService.updateOpenDoorHistoryById(history);

                String msg = assembleOpenDoorMsg(shop.getName(), shop.getAddress(), "门禁小程序用户扫码开门", DateUtil.formatDateTime(new Date()), phone);
                qiYeWeChatSendMsgUtil.sendMarkdownMsg(OPEN_DOOR_QI_YE_WECHAT_GROUP_01_KEY, msg);
            }
        }
        return 1;
    }

    @Override
    public DriverOpenDoorVO driverOpenDoor(OpenDoorRequest request) throws BizException {

        DriverOpenDoorVO vo = new DriverOpenDoorVO();

        Integer shopId = request.getShopId();
        Shop shop = shopService.getShopById(shopId);
        Integer userId = request.getUserId();
        String phone = request.getPhone();
        Double lnt1 = request.getLnt();
        Double lat1 = request.getLat();

        OpenDoorHistory history = new OpenDoorHistory();
        history.setWxMiniUserId(userId);
        history.setPhone(phone);
        history.setShopId(shopId);
        history.setShopName(shop.getName());
        history.setOpenTime(new Date());
        history.setLocation(lnt1 + "," + lat1);
        history.setSendResult(0);
        history.setOpenType(2);
        openDoorHistoryService.addOpenDoorHistory(history);

        // 先校验骑手位置
        // 计算用户所在位置是否在商店附近1000米范围内
        Double lnt2 = shop.getLnt();
        Double lat2 = shop.getLat();
        double distance = DistanceUtils.getDistanceByHaversine(lnt1, lat1, lnt2, lat2);

        Integer id = history.getId();
        log.info("addOpenDoorHistory Id 主键id返回 = {}", id);

        if (distance > 1) {
            log.info("driverOpenDoor Error 门店id={},门店经纬度=【{},{}】用户所在经纬度=【{},{}】距离={}千米,phone={}", shopId, lnt1, lat1, lnt2, lat2, distance, phone);
            throw new BizException(BizExceptionEnum.DISTANCE_MUST_IN_100);
        }

        // 再校验取货码
        MeiTuanOrder meiTuanOrderByOrderCode = mtService.getMeiTuanOrderByOrderCode(request.getOrderCode(), shop.getStoreId());
        MeiTuanOrder meiTuanOrderByPhoneCode = mtService.getMeiTuanOrderByPhoneCode(request.getOrderCode(), shop.getStoreId());
        MeiTuanOrder realOrder = null;
        // 只要手机号后四位或者订单后四位正确，则开门成功
        if (meiTuanOrderByOrderCode == null && meiTuanOrderByPhoneCode == null) {
            log.info("driverOpenDoor orderCodeError 取货码错误 code={},shopId={},门店经纬度=【{},{}】用户所在经纬度=【{},{}】距离={}千米,phone={}", request.getOrderCode(), shopId, lnt1, lat1, lnt2, lat2, distance, phone);
            throw new BizException(BizExceptionEnum.DRIVER_ORDER_CODE_IS_ERROR);
        }
        if (meiTuanOrderByOrderCode != null) {
            realOrder = meiTuanOrderByOrderCode;
        }
        if (meiTuanOrderByPhoneCode != null) {
            realOrder = meiTuanOrderByPhoneCode;
        }

        // 直接发起开门指令
        String result = iotService.userOpenDoorByMini(shopId, phone);
        log.info("driverOpenDoor 开门 门店id={},门店经纬度=【{},{}】用户所在经纬度=【{},{}】距离={}千米,phone={},开门响应={}", shopId, lnt1, lat1, lnt2, lat2, distance, phone, result);
        if ("发送成功".equals(result)) {
            // 更新状态为下发成功
            history.setSendResult(1);
            history.setUpdateTime(new Date());
            openDoorHistoryService.updateOpenDoorHistoryById(history);

            String msg = assembleOpenDoorMsg(shop.getName(), shop.getAddress(), "门禁小程序骑手扫码开门", DateUtil.formatDateTime(new Date()), phone);
            qiYeWeChatSendMsgUtil.sendMarkdownMsg(OPEN_DOOR_QI_YE_WECHAT_GROUP_01_KEY, msg);
        }
        if (null != realOrder) {
            // 返回美团主订单id
            vo.setOrderId(realOrder.getId());
            vo.setPlatformDayId(realOrder.getPlatformDayId());
            vo.setOrderAmount(realOrder.getOrderAmount());
            vo.setOrderReceivableAmount(realOrder.getOrderReceivableAmount());
            vo.setCreateTime(realOrder.getCreateTime());
        }
        return vo;
    }
}

